package resoft.jeasyform.components;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;
import java.lang.reflect.Method;

import charvax.swing.JOptionPane;
import charvax.swing.JFrame;
import resoft.jeasyform.event.EventHandler;
import resoft.jeasyform.event.EventType;
import resoft.jeasyform.core.WindowRunner;
import charva.awt.event.KeyListener;
import charva.awt.event.KeyEvent;

/**
 * <p>Description of Window</p>
 * User: albert
 * Date: Aug 26, 2007
 * Time: 7:50:44 PM
 */
public class Window {
    private static final Log logger = LogFactory.getLog(Window.class);

    private static final int StatusBarY = 20;
    private static final int StatusBarX = 10;

    public Window() {
        setupConfirmBar();
    }

    private void setupConfirmBar() {
        //add comfire bar
        confirmMsg = new Label();
        String msg = getProperty("ConfirMessage");
        if (msg.equals("")) {
            msg = "Please confire to continue:(Y/N)";
        }
        confirmMsg.setText(msg);
        confirmMsg.setRectangle(StatusBarX, StatusBarY, 30, 1);
        confirmMsg.hide();
        components.add(confirmMsg);

        confirmValue = new TextField();
        confirmValue.setRectangle(StatusBarX + 33, StatusBarY, 2, 1);
        confirmValue.setValue("Y");
        confirmValue.hide();
        components.add(confirmValue);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHegith() {
        return hegith;
    }

    public void setHegith(int hegith) {
        this.hegith = hegith;
    }

    /**
     * set property
     *
     * @param name  String
     * @param value String
     */
    public void setProperty(String name, String value) {
        properties.put(name, value);
    }

    /**
     * get property
     *
     * @param key String
     * @return String
     */
    public String getProperty(String key) {
        String value = (String) properties.get(key);
        return value == null ? "" : value;
    }

    /**
     * set parameters
     *
     * @param parameterMap Map
     */
    public void setParameterMap(Map parameterMap) {
        if (parameterMap != null) {
            this.parameterMap = parameterMap;
        }
    }

    /**
     * get parameter value by name
     *
     * @param name String
     * @return Object
     */
    public Object getParameter(String name) {
        return parameterMap.get(name);
    }

    public void setJFrame(JFrame jFrame) {
        this.jFrame = jFrame;
    }

    /**
     * add a component
     *
     * @param component Component
     */
    public void add(Component component) {
        components.add(component);
    }

    /**
     * list all components
     *
     * @return Collection
     */
    public List listAllComponents() {
        return components;
    }

    /**
     * setContainer
     *
     * @param container JComponent
     */
    public void setContainer(charva.awt.Component container) {
        this.container = container;
    }

    /**
     * changeFocus
     *
     * @param source Component to change
     */
    public void changeFocus(Component source) {
        int index = components.indexOf(source);
        //index++;
        
        while (true) {
            index ++;
            if(index>=components.size()) {
                index = -1;
                continue;
            }
            Component obj = (Component) components.get(index);
            if(obj==source) {
                break;
            }
            if (obj instanceof AcceptFocusAware && obj.isAccpetFocus()) {
                AcceptFocusAware control = (AcceptFocusAware) obj;
                control.requestFocus();
                break;
            }
            //index++;
        }
    }

    /**
     * set statusBar
     *
     * @param title   String
     * @param initMsg String
     */
    public void setupStatusBar(String title, String initMsg) {
        //add status bar
        statusBarTitle.setRectangle(0, StatusBarY, 10, 1);
        statusBar.setRectangle(StatusBarX, StatusBarY, 40, 1);

        components.add(statusBarTitle);
        components.add(statusBar);

        statusBarTitle.setText(title);
        statusBar.setText(initMsg);
    }

    /**
     * get menu
     *
     * @return Menu return this window 's single menu
     * */
    public Menu getMenu() {
        return menu;
    }

    /**
     * set statusBar message
     *
     * @param msg String
     */
    public void setMessage(String msg) {
        statusBar.setText(msg);
    }


    public void registerInitEvent(EventHandler initHandler) {
        this.initHandler = initHandler;
    }

    /**
     * invokeInitEvent
     */
    public void invokeInitEvent() {
        //set focus to first
        changeFocus(null);

        if (initHandler != null) {
            initHandler.execute(this, null, EventType.WindowInitEvent);
        }
    }

    /**
     * show window
     *
     * @param msg String
     */
    public void showMessageBox(String msg) {
        JOptionPane.showMessageDialog(container, msg,"",JOptionPane.DEFAULT_OPTION);
    }

    /**
     * open a new window and close this one
     *
     * @param windowName String the will want to open
     * @param params     Map
     */
    public void openWindow(String windowName, Map params) {
        this.close();
        WindowRunner.openWindow(windowName, params);
    }

    /**
     * close this window
     */
    public void close() {
        jFrame.hide();
    }

    /**
     * waitConfirmation
     *
     * @param msg   String
     * @param event EventHandler This event will trigger after confirmation.
     *              if user input no,this event will NOT be triggerd.
     *              <p/>
     */
    public void waitConfirmation(String msg, final EventHandler event) {
        //save current focus
        charva.awt.Component currFocus = jFrame.getCurrentFocus();

        confirmMsg.show();
        confirmValue.show();
        statusBar.hide();

        confirmValue.requestFocus();
        confirmValue.getSwingObject().addKeyListener(new ConfirmKeyListener(this,event,currFocus));
    }

    private class ConfirmKeyListener implements KeyListener {
        ConfirmKeyListener(Window window,EventHandler afterConfirmEvent,charva.awt.Component currFocus) {
            this.window = window;
            this.afterConfirmEvent = afterConfirmEvent;
            this.currFocus = currFocus;
        }
        public void keyPressed(KeyEvent keyEvent) {
            int keyCode = keyEvent.getKeyCode();
            if (keyCode == 89 || keyCode == 121) {
                //pressed y or Y.invoke event.close confirm bar
                afterConfirmEvent.execute(window,null,EventType.ConfirmationEvent);
                closeConfirm();
            } else if (keyCode == 78 || keyCode == 110) {
                //pressed n or N.Don't invoke event.close confirm bar
                closeConfirm();
            } 
             keyEvent.consume();
        }

        private void closeConfirm() {
            confirmMsg.hide();
            confirmValue.hide();
            statusBar.show();
            currFocus.requestFocus();
            confirmValue.setValue("Y");
        }

        public void keyTyped(KeyEvent ke_) {

        }

        public void keyReleased(KeyEvent ke_) {

        }
        private Window window;
        private EventHandler afterConfirmEvent;
        private charva.awt.Component currFocus;
    }


    /**
     * get componenet's attribute
     *
     * @param name String
     * @param key  String
     * @return String
     */
    public String getComponentAttribute(String name, String key) {
        Component target = findComponentByName(name);
        if (target != null) {
            String methodName = "get" + key;
            Method[] methodArray = target.getClass().getMethods();
            for (int i = 0; i < methodArray.length; i++) {
                Method method = methodArray[i];
                if (method.getName().equalsIgnoreCase(methodName)) {
                    try {
                        return (String) method.invoke(target, new Object[]{});
                    } catch (Exception e) {
                        logger.error("getAttribute Error");
                    }
                }
            }
        }
        return null;
    }

    /**
     * get field's value
     *
     * @param name String field's name
     * @return String the field's value
     */
    public String getValue(String name) {
        return getComponentAttribute(name, "value");
    }

    /**
     * change component's attribute
     *
     * @param name  String
     * @param key   String
     * @param value String
     */
    public void changeComponent(String name, String key, String value) {
        Component target = findComponentByName(name);
        //change attribute
        //Class[] paramterTypes = new Class[] {String.class};
        if (target != null) {
            String methodName = "set" + key;
            //Method method = target.getClass().getMethod(")
            Method[] methodArray = target.getClass().getMethods();
            for (int i = 0; i < methodArray.length; i++) {
                Method method = methodArray[i];
                if (method.getName().equalsIgnoreCase(methodName)) {
                    try {
                        method.invoke(target, new Object[]{value});
                    } catch (Exception e) {
                        logger.error("invoke method error:" + name + ";" + key + ";" + value);
                    }
                    break;
                }
            }
        }
    }

    public Component findComponentByName(String name) {
        Component target = null;
        for (Iterator itr = components.iterator(); itr.hasNext();) {
            Component component = (Component) itr.next();
            if (component.getName().equalsIgnoreCase(name)) {
                target = component;
                break;
            }
        }
        return target;
    }


    private String title;
    private int width = 80;
    private int hegith = 24;

    private JFrame jFrame;

    private Map properties = new HashMap();

    private Map parameterMap = new HashMap();

    private List components = new ArrayList();

    private Label statusBarTitle = new Label();
    private Label statusBar = new Label();


    //waitConfirmation message and input field
    private Label confirmMsg;
    private InputField confirmValue;

    private Menu menu = new Menu();

    private charva.awt.Component container;

    private EventHandler initHandler;


}
